#include "stdafx.h"
#include "WtlEditBrowserCtrl.h"
/*
Module : WtlEditBrowserCtrl.cpp
Purpose: Interface for an WTL class which provides a edit control with browse button 
Copyright (c) 2003 by iLYA Solnyshkin. 
E-mail: isolnyshkin@yahoo.com 
All rights reserved.

 Big thanks Pete Arends for your MFC-control( http://www3.telus.net/pja/CFileEditCtrl.htm ).
*/

static const int		kBrushWidth		= 8;
static const int		kBrushHeight	= 8;

CWtlEditBrowserCtrl::CWtlEditBrowserCtrl() :	m_nButtonState(BTN_UP),
												m_nButtonWidth(-1),
												m_bMouseCaptured(FALSE)
{
m_rcButtonRect.SetRectEmpty();
}


BOOL 
CWtlEditBrowserCtrl::SubclassWindow( HWND hWnd )
{
CRect	rectCtl;
BOOL	bRet = CWindowImpl<CWtlEditBrowserCtrl, CEdit>::SubclassWindow( hWnd );

::GetWindowRect(m_hWnd, &rectCtl);
::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rectCtl, 2);
SetWindowPos(NULL, &rectCtl, SWP_FRAMECHANGED);

return bRet;
}

LRESULT 
CWtlEditBrowserCtrl::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DefWindowProc( uMsg, wParam, lParam );
return 0;
}

LRESULT 
CWtlEditBrowserCtrl::OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DefWindowProc( uMsg, wParam, lParam );
DrawButton(m_nButtonState);     // draw the button in its current state
return 0;
}

void 
CWtlEditBrowserCtrl::DrawButton(int nButtonState)
{
if (m_rcButtonRect.Width() < 3 || m_rcButtonRect.Height() < 3)
    return;	// if the button is too small, do not draw it

    // if the control is disabled, ensure the button is drawn disabled
if (GetStyle() & WS_DISABLED)
	nButtonState = BTN_DISABLED;

CDC			dc;
CBitmap		bmOffscreen;
CWindowDC	dcWnd(m_hWnd);
CRect		rDraw(m_rcButtonRect);
    
rDraw.OffsetRect(0 - m_rcButtonRect.left, 0 - m_rcButtonRect.top);

// Create a memory dc to prevent flicker
dc.CreateCompatibleDC(dcWnd);
int savedDC = dc.SaveDC();
bmOffscreen.CreateCompatibleBitmap(dcWnd, m_rcButtonRect.Width(), m_rcButtonRect.Height());
dc.SelectBitmap(bmOffscreen);
dc.FillSolidRect(&rDraw, ::GetSysColor(COLOR_3DFACE));
if (nButtonState == BTN_DOWN)
    {
    CPen	pen,
			pPenOld;
    // draw the border
	pen.CreatePen( PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
	pPenOld = dc.SelectPen(pen);
    dc.Rectangle(rDraw);
    dc.SelectPen(pPenOld);
    pen.DeleteObject();

    DrawDots(dc, GetSysColor(COLOR_BTNTEXT), 1);
    }
else    // draw button as up
    {
        // draw the border
	if (m_nButtonState & BTN_FLAT)
        {
        CPen	pen,
				pPenOld;
				
		pen.CreatePen( PS_SOLID, 1, GetSysColor(COLOR_WINDOW));
        pPenOld = dc.SelectPen(pen);
        dc.Rectangle(rDraw);
        dc.SelectPen(pPenOld);
        pen.DeleteObject();
        }
	else
		dc.DrawEdge(rDraw, EDGE_RAISED, BF_RECT);

	if (nButtonState & BTN_DISABLED)
        {
		DrawDots(dc, GetSysColor(COLOR_3DHILIGHT), 1);
		DrawDots(dc, GetSysColor(COLOR_3DSHADOW));
        }
	else if (nButtonState & BTN_UP)
        {
        COLORREF	clrDots = GetSysColor(COLOR_BTNTEXT);
        
        if ((m_nButtonState & BTN_FLAT))
			{
            int grayscale = (((GetBValue(clrDots) * 11) + (GetGValue(clrDots) * 59) + (GetRValue(clrDots) * 30)) / 100);
            clrDots = RGB(grayscale, grayscale, grayscale);
			}
			
        DrawDots(dc, clrDots);
        }
	else
        {
		ATLASSERT(FALSE);  // Invalid nButtonState
        }
    }

m_nButtonState = (m_nButtonState & BTN_FLAT) ? nButtonState | BTN_FLAT : nButtonState;
//
// Blit the button image onto the screen and clean up 
//
dcWnd.BitBlt(	m_rcButtonRect.left, m_rcButtonRect.top,
				m_rcButtonRect.Width(), m_rcButtonRect.Height(),
				dc, 0, 0, SRCCOPY);
dc.RestoreDC(savedDC);
bmOffscreen.DeleteObject();
}

void CWtlEditBrowserCtrl::DrawDots(CDC& pDC, COLORREF CR, int nOffset /* = 0 */)
{
    int width = m_rcButtonRect.Width();         // width of the button
    div_t divt = div(width, 4);
    int delta = divt.quot;                      // space between dots
    int left = width / 2 - delta - (divt.rem ? 0 : 1); // left side of first dot
    width = width / 10;                         // width and height of one dot
    int top = m_rcButtonRect.Height() / 2 - width / 2;  // top of dots
    left += nOffset;                            // draw dots shifted? (for button pressed)
    top += nOffset;
    // draw the dots
    if (width < 2)
    {
        pDC.SetPixelV(left, top, CR);
        left += delta;
        pDC.SetPixelV(left, top, CR);
        left += delta;
        pDC.SetPixelV(left, top, CR);
    }
    else
    {
        CPen thePen;
		thePen.CreatePen(PS_SOLID, 1, CR);           // set the dot colour
        CPen pOldPen = pDC.SelectPen(thePen);
        CBrush theBrush;
		theBrush.CreateSolidBrush(CR);
        CBrush pOldBrush = pDC.SelectBrush(theBrush);
        pDC.Ellipse(left, top, left + width, top + width);
        left += delta;
        pDC.Ellipse(left, top, left + width, top + width);
        left += delta;
        pDC.Ellipse(left, top, left + width, top + width);
        pDC.SelectBrush(pOldBrush);           // reset the DC
        theBrush.DeleteObject();
        pDC.SelectPen(pOldPen);
        thePen.DeleteObject();
    }
}

LRESULT CWtlEditBrowserCtrl::OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	DefWindowProc( uMsg, wParam, lParam );

	NCCALCSIZE_PARAMS FAR* lpncsp = (NCCALCSIZE_PARAMS FAR*)lParam;
	
	// if m_nButtonWidth is -1, set the button width to 80% of the control height
    // else set the button width to m_nButtonWidth
    int ButtonWidth = (m_nButtonWidth == -1) ? (lpncsp->rgrc[0].bottom - lpncsp->rgrc[0].top) * 8/10 : m_nButtonWidth;
    
    // set button area equal to client area of edit control
    m_rcButtonRect = lpncsp->rgrc[0];
    
    // draw the button on the right side of the control
    // shrink right side of client area by the button width
    // and add a one pixel neutral area between button and client area
    int neutral = /*ButtonWidth > 2 ? 1 :*/ 0;
    lpncsp->rgrc[0].right -= ButtonWidth + neutral;
    // shrink the button so its left side is at the right side of client area
    m_rcButtonRect.left = lpncsp->rgrc[0].right + neutral;

    if ((BOOL)wParam)
        // convert button coordinates from parent client coordinates to control window coordinates
        m_rcButtonRect.OffsetRect(-lpncsp->rgrc[1].left, -lpncsp->rgrc[1].top);
    m_rcButtonRect.NormalizeRect();
	return 0;
}

LRESULT CWtlEditBrowserCtrl::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	UINT where = DefWindowProc( uMsg, wParam, lParam );
    if (where == HTNOWHERE && ScreenPointInButtonRect(CPoint (GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))))
        where = HTBORDER;
    return where;
}

BOOL CWtlEditBrowserCtrl::ScreenPointInButtonRect(CPoint point)
{
    CRect ControlRect;
    GetWindowRect(&ControlRect);
    // convert point from screen coordinates to window coordinates
    point.Offset(-ControlRect.left, -ControlRect.top);
    return m_rcButtonRect.PtInRect(point);
}

LRESULT CWtlEditBrowserCtrl::OnNcLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	DefWindowProc( uMsg, wParam, lParam );
	
    if (ScreenPointInButtonRect(CPoint (GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))))
    {
        SetFocus();
        SetCapture();
        m_bMouseCaptured = TRUE;
        DrawButton(BTN_DOWN);
    }
	return 0;
}

LRESULT CWtlEditBrowserCtrl::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	DefWindowProc( uMsg, wParam, lParam );
    if (m_bMouseCaptured)
    {
		CPoint point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
        ReleaseCapture();
        m_bMouseCaptured = FALSE;
        if (m_nButtonState != BTN_UP)
            DrawButton(BTN_UP);
        ClientToScreen(&point);
        if (ScreenPointInButtonRect(point))
            ButtonClicked();
    }
	return 0;
}

void CWtlEditBrowserCtrl::ButtonClicked()
{
TCHAR	szPath[MAX_PATH+1];

::ZeroMemory(szPath, sizeof(szPath));
if (SendMessage(GetParent(), WMU_BROWSE, WPARAM(m_hWnd), LPARAM(szPath)))
	SetWindowText(szPath);
}